﻿using System;

namespace SharpDepend.Architecture.Windows
{
    public interface IBaseControllable<TApplication>
    {
        IController<TApplication> Controller { get; }
    }

    public interface IBasePage<TApplication> : IBaseControllable<TApplication>
    {

    }

    public interface IBaseVisualComponent<TContext> : IBaseControllable<TContext>
    {

    }

    public interface IVisualComponent<TController, TApplication>
        : IBaseVisualComponent<TApplication>, IViewer<TController, TApplication> where TController : class, IController<TApplication>
    {
    }

    public interface IPage<TController, TApplication>
        : IBasePage<TApplication>, IViewer<TController, TApplication> where TController : class, IController<TApplication>
    {
    }

    public interface IViewer<TController, TApplication> : IBasePage<TApplication> where TController : class, IController<TApplication>
    {
        /// <summary>
        /// Must be called in the viewer constructor.
        /// </summary>
        /// <returns></returns>
        new TController Controller { get; }
    }

    public interface IController<TApplication> : IDisposable
    {
        void Initialize(TApplication application);
    }

    public abstract class Controller<TViewer, TApplication> : IController<TApplication>
    {
        protected TViewer Viewer { get; private set; }

        public TApplication Context { get; private set; }

        /// <summary>
        /// Viewer as component will be stored at the back end.
        /// </summary>
        /// <param name="viewer">Viewer (GUI)</param>
        public Controller(TViewer viewer)
        {
            if (viewer == null)
            {
                throw new ArgumentNullException(nameof(viewer));
            }

            this.Viewer = viewer;
        }

        public Controller(TApplication context, TViewer viewer)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (viewer == null)
            {
                throw new ArgumentNullException(nameof(viewer));
            }

            SetContext(context);
            this.Viewer = viewer;
        }

        public abstract void Dispose();

        internal void SetContext(TApplication context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            Context = context;
        }

        void IController<TApplication>.Initialize(TApplication application)
        {
            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            SetContext(application);
        }
    }
}
